package io.singulart.pulse_button;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.image.PixelMap;

public class PulseButton extends Component implements Component.DrawTask {
    private static final int DEFAULT_ALPHA = 255;

    private EventHandler mHandler = new EventHandler(EventRunner.getMainEventRunner());
    private Paint mCirclePaint;
    private Paint mCircleStrokeInnerPaint;
    private Paint mCircleStrokeOuterPaint;

    private int mPbColorCenterCircle = Color.WHITE.getValue();
    private int mPbColorCenterCircleStroke = Color.WHITE.getValue();
    private int[] mPbColorWaveCircleStrokeArr;

    private float mPbWavePadding = 10;
    private float mPbWavePaddingInterAct;

    private float mPbInnerCircleStrokePadding;

    private float mPbInnerCircleStrokeWidth = 2;
    private float mPbOuterCircleStrokeWidth = 2;

    private float mPbPulseSpeed = 90;

    private int mPbColorWaveCircleStrokeColor = Color.WHITE.getValue();

    private PixelMap mBmIcon;

    private RectFloat mSrcRect;

    public PulseButton(Context context) {
        this(context, null);
    }

    public PulseButton(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public PulseButton(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(attrSet);
    }

    private void init(AttrSet attrSet) {
        if (attrSet != null) {
            mPbColorCenterCircle = AttrUtils.getAttrSetColor(attrSet, "pb_color_center_circle", Color.WHITE);
            mPbColorCenterCircleStroke =
                    AttrUtils.getAttrSetColor(attrSet, "pb_color_center_circle_stroke", Color.WHITE);

            mPbWavePadding = AttrUtils.getDimension(attrSet, "pb_wave_padding", 10);
            mPbWavePaddingInterAct = mPbWavePadding;
            mPbInnerCircleStrokePadding = AttrUtils.getDimension(attrSet, "pb_inner_circle_stroke_padding", 20);
            mPbColorWaveCircleStrokeColor =
                    AttrUtils.getAttrSetColor(attrSet, "pb_color_wave_circle_stroke", Color.WHITE);

            mPbPulseSpeed = AttrUtils.getInt(attrSet, "pb_pulse_speed", 90);

            mPbInnerCircleStrokeWidth = AttrUtils.getDimension(attrSet, "pb_stroke_width_of_center_circle", 2);
            mPbOuterCircleStrokeWidth = AttrUtils.getDimension(attrSet, "pb_stroke_width_of_outer_circle", 2);
        }
        mPbColorWaveCircleStrokeArr = getARGB(mPbColorWaveCircleStrokeColor);
        initDef();
        addDrawTask(this);
    }

    /**
     * set PbColorCenterCircleStroke
     *
     * @param pbColorCenterCircleStroke int
     */
    public void setPbColorCenterCircleStroke(int pbColorCenterCircleStroke) {
        this.mPbColorCenterCircleStroke = pbColorCenterCircleStroke;
        if (mCircleStrokeInnerPaint != null) {
            mCircleStrokeInnerPaint.setColor(new Color(pbColorCenterCircleStroke));
        }
    }

    /**
     * set PbInnerCircleStrokePadding
     *
     * @param pbInnerCircleStrokePadding float
     */
    public void setPbInnerCircleStrokePadding(float pbInnerCircleStrokePadding) {
        this.mPbInnerCircleStrokePadding = pbInnerCircleStrokePadding;
    }

    /**
     * set PbColorWaveCircleStrokeColor
     *
     * @param pbColorWaveCircleStrokeColor int
     */
    public void setPbColorWaveCircleStrokeColor(int pbColorWaveCircleStrokeColor) {
        this.mPbColorWaveCircleStrokeColor = pbColorWaveCircleStrokeColor;
        mPbColorWaveCircleStrokeArr = getARGB(pbColorWaveCircleStrokeColor);
    }

    /**
     * set PbPulseSpeed
     *
     * @param pbPulseSpeed float
     */
    public void setPbPulseSpeed(float pbPulseSpeed) {
        this.mPbPulseSpeed = pbPulseSpeed;
    }

    /**
     * set PbInnerCircleStrokeWidth
     *
     * @param pbInnerCircleStrokeWidth float
     */
    public void setPbInnerCircleStrokeWidth(float pbInnerCircleStrokeWidth) {
        this.mPbInnerCircleStrokeWidth = pbInnerCircleStrokeWidth;
        if (mCircleStrokeInnerPaint != null) {
            mCircleStrokeInnerPaint.setStrokeWidth(pbInnerCircleStrokeWidth);
        }
    }

    /**
     * set PbOuterCircleStrokeWidth
     *
     * @param pbOuterCircleStrokeWidth float
     */
    public void setPbOuterCircleStrokeWidth(float pbOuterCircleStrokeWidth) {
        this.mPbOuterCircleStrokeWidth = pbOuterCircleStrokeWidth;
        if (mCircleStrokeOuterPaint != null) {
            mCircleStrokeOuterPaint.setStrokeWidth(pbOuterCircleStrokeWidth);
        }
    }

    /**
     * set PbWavePadding
     *
     * @param pbWavePadding float
     */
    public void setPbWavePadding(float pbWavePadding) {
        this.mPbWavePadding = pbWavePadding;
        mPbWavePaddingInterAct = pbWavePadding;
    }

    /**
     * set BmIcon
     *
     * @param bmIcon PixelMap
     */
    public void setBmIcon(PixelMap bmIcon) {
        this.mBmIcon = bmIcon;
        initDef();
    }

    private void initDef() {
        if (mCirclePaint == null) {
            mCirclePaint = new Paint();
            mCirclePaint.setAntiAlias(true);
            mCirclePaint.setSubpixelAntiAlias(true);
            mCirclePaint.setStyle(Paint.Style.FILL_STYLE);
        }
        mCirclePaint.setColor(new Color(mPbColorCenterCircle));
        if (mCircleStrokeInnerPaint == null) {
            mCircleStrokeInnerPaint = new Paint();
            mCircleStrokeInnerPaint.setAntiAlias(true);
            mCircleStrokeInnerPaint.setSubpixelAntiAlias(true);
            mCircleStrokeInnerPaint.setStyle(Paint.Style.STROKE_STYLE);
        }

        mCircleStrokeInnerPaint.setColor(new Color(mPbColorCenterCircleStroke));
        mCircleStrokeInnerPaint.setStrokeWidth(mPbInnerCircleStrokeWidth);

        if (mCircleStrokeOuterPaint == null) {
            mCircleStrokeOuterPaint = new Paint();
            mCircleStrokeOuterPaint.setAntiAlias(true);
            mCircleStrokeOuterPaint.setSubpixelAntiAlias(true);
            mCircleStrokeOuterPaint.setStyle(Paint.Style.STROKE_STYLE);
        }

        int cc =
                Color.argb(
                        mPbColorWaveCircleStrokeArr[0],
                        mPbColorWaveCircleStrokeArr[1],
                        mPbColorWaveCircleStrokeArr[2],
                        mPbColorWaveCircleStrokeArr[3]);
        mCircleStrokeOuterPaint.setColor(new Color(cc));
        mCircleStrokeOuterPaint.setStrokeWidth(mPbOuterCircleStrokeWidth);

        if (mSrcRect == null) {
            mSrcRect = new RectFloat();
        }
        if (mBmIcon != null) {
            mSrcRect.left = (int) (getCenterWidth() - (mBmIcon.getImageInfo().size.width / 2F)) + 4;
            mSrcRect.top = (int) (getCenterHeight() - (mBmIcon.getImageInfo().size.height / 2F));
            mSrcRect.right = (int) (getCenterWidth() + (mBmIcon.getImageInfo().size.width / 2F)) + 4;
            mSrcRect.bottom = (int) getCenterHeight() + (mBmIcon.getImageInfo().size.height / 2f);
        }
        invalidate();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.drawCircle(getCenterWidth(), getCenterHeight(), getRadius(), mCirclePaint);
        canvas.drawCircle(
                getCenterWidth(),
                getCenterHeight(),
                getRadius() - mPbInnerCircleStrokePadding,
                mCircleStrokeInnerPaint);

        float alpha = (mPbWavePaddingInterAct / mPbWavePadding) * DEFAULT_ALPHA;

        if (alpha > 0) {
            mCircleStrokeOuterPaint.setAlpha(alpha / DEFAULT_ALPHA);
            canvas.drawCircle(getCenterWidth(), getCenterHeight(), getWaveRadius(), mCircleStrokeOuterPaint);
        }

        if (mPbWavePaddingInterAct <= 0) {
            mPbWavePaddingInterAct = mPbWavePadding;
        } else {
            mPbWavePaddingInterAct -= mPbWavePadding / mPbPulseSpeed;
        }

        if (mBmIcon != null) {
            canvas.drawPixelMapHolderRect(new PixelMapHolder(mBmIcon), mSrcRect, new Paint());
        }
        mHandler.postTask(this::invalidate);
    }

    private float getCenterWidth() {
        return getWidth() / 2F;
    }

    private float getCenterHeight() {
        return getHeight() / 2F;
    }

    private float getWaveRadius() {
        return (getWidth() > getHeight() ? getHeight() / 2F : getWidth() / 2F) - mPbWavePaddingInterAct;
    }

    private float getRadius() {
        return (getWidth() > getHeight() ? getHeight() / 2F : getWidth() / 2F) - mPbWavePadding;
    }

    private int[] getARGB(int color) {
        int[] lineColor = new int[4];
        lineColor[0] = Color.alpha(color);
        RgbColor rgbColor = new RgbColor(color);
        lineColor[1] = rgbColor.getRed();
        lineColor[2] = rgbColor.getGreen();
        lineColor[3] = rgbColor.getBlue();
        return lineColor;
    }
}
